Exercise (Week 8)
Table of Contents
DUE: 29 April, 2018 23:55
Download the exercise tarball and extract it to a directory in your
home directory at CSE. This tarball contains a file, called Ex06.hs
,
wherein you will do all of your programming.
To test your code, run the following shell commands to open a GHCi session:
$ 3141 newclass starting new subshell for class COMP3141... $ cabal repl Resolving dependencies... Configuring Ex06-1.0... Preprocessing executable 'Ex06' for Ex06-1.0.. GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Ex06 (Ex06.hs, interpreted) Ok, one module loaded. *Ex06> let f = L "Hi " $ S $ L "! You're " $ I $ L "years old" $ X *Ex06> printf f "Bob" 3 ...
Note that you will only need to submit Ex06.hs
, so only make changes
to that file.
Download the exercise tarball and extract it to a directory on
your local machine. This tarball contains a file, called Ex06.hs
,
wherein you will do all of your programming.
To test your code, run the following shell commands to open a GHCi session:
$ stack repl Configuring GHCi with the following packages: Ex06 Using main module: 1. Package 'Ex06' component exe:Ex06 ... GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Ex06 (Ex06.hs, interpreted) Ok, one module loaded. *Ex06> let f = L "Hi " $ S $ L "! You're " $ I $ L "years old" $ X *Ex06> printf f "Bob" 3 ...
Note that you will only need to submit Ex06.hs
, so only make changes
to that file.
Download the Haskell for Mac project and unzip it somewhere on your
local machine. Open the project in Haskell for Mac, and begin
coding in Ex06.hs
.
Note that you will only need to submit Ex06.hs
, so only make changes
to that file.
Recall the C function printf
, which splices values into a special kind of string, called a format string:
// Prints "Hello Bob, you are 3 years old". printf("Hello %s! you are %d years old!","Bob",3)
The problem with this C function is that it's not type-safe. The types (and number) of the remaining
arguments to printf
are dependent on the value of first one – the format string. This makes encoding
a printf
style function in Haskell seem perhaps a bit more difficult than in less type-safe languages.
Note: For simplicity, our printf
function will produce a pure String output rather than print to the screen.
General idea: Implement a GADT called Format
for format strings, indexed by a type-level list of types required to fill the format string.
Then, implement the printf
function with the corresponding type.
1 Implement the Format GADT (4 Marks)
Instead of using plain old strings for our format strings, we're going to use a special data type, a GADT, indexed by a type-level list of types required by the format.
Complete the following GADT, Format
, using the examples below as a guide:
data Format (fmt :: [*]) where X :: Format '[] L :: {- your type here -} S :: {- your type here -} I :: {- your type here -}
The '
in front of the []
data constructor is important: it tells the compiler that the following constructor
is a data constructor (namely the constructor for the empty list) which should be lifted to the type level.
If you use the cons operator :
on the type level, you will need to preceed it with '
as well.
1.1 Examples of Format Strings (and their types)
(L "Hello " (S (L "! You are " (I (L " years old!" X))))) :: Format '[String, Int]
Or, using the $
operator to make it clearer:
L "Hello " $ S $ L "! You are " $ I $ L " years old!" $ X :: Format '[String, Int]
Another example:
S $ S $ S $ I $ I $ I $ X :: Format '[String, String, String, Int, Int, Int]
And another:
L "Hello " $ L "World" $ X :: Format '[]
2 Implement printf
(5 Marks)
Here is a type family we use to compute the type of printf
given a format string:
type family FormatArgsThen (fmt :: [*]) (ty :: *) type instance FormatArgsThen '[] ty = ty type instance FormatArgsThen (t ': fmt) ty = t -> FormatArgsThen fmt ty
Then, our printf
function is simply of type:
printf :: Format fmt -> FormatArgsThen fmt String
You can see how this works by manually expanding the type family:
printf (L "Hello " $ S $ L "! You are " $ I $ L " years old!" $ X) :: FormatArgsThen '[String, Int] String :: String -> FormatArgsThen '[Int] String :: String -> Int -> FormatArgsThen '[] String :: String -> Int -> String
Actually implementing the printf
function is harder than it looks, and that's where you come in.
Implement the printf
function so that it produces a string consisting of the argument values spliced in to the appropriate placeholders in the format string.
You may find it helpful to define printf
itself as:
printf :: Format fmt -> FormatArgsThen fmt String printf f = printf' f ""
Where printf'
is a function of similar type, except that it takes an additional string parameter for the "output so far" — the accumulator:
printf' :: Format fmt -> String -> FormatArgsThen fmt String {- YOUR CODE HERE -}
3 Submission instructions
$ give cs3141 Ex06 Ex06.hs
on a CSE terminal, or by using the give
web interface. Your file must be named Ex06.hs
(case-sensitive!).
A dry-run test will partially autotest your solution at submission time. To get full marks, you will need to
perform further testing yourself.